package com.yqh.Collection.Set;

import lombok.*;

import java.util.HashSet;

/**
 * HashSet 集合的底层原理
 *
 * @author 阳秋豪
 * @createTime 2024/3/6
 */
public class Test1 {
    public static void main(String[] args) {
        /*------------------------- 前置知识 -------------------------*/
        // 1、哈希值
        // -- 就是一个int类型的数值，Java中每个对象都有一个哈希值。
        // -- Java中的所有对象，都可以调用 Object 类提供的 hashCode 方法，返回该对象自己的哈希值。

        // 2、对象哈希值的特点
        // -- 同一个对象多次调用hashcode()方法返回的哈希值是相同的。
        // -- 不同的对象，它们的哈希值一般不相同，但也有可能会相同(哈希碰撞)。

        /*--------------------- HashSet 底层原理 ---------------------*/
        // HashSet 基于哈希表实现。
        // 1、JDK8 之前，哈希表 = 数组 + 链表
        // ① 创建一个默认长度16的数组，默认加载因子为0.75（扩容用的），数组名table
        // ② 使用元素的哈希值对数组的长度求余计算出应存入的位置
        // ③ 判断当前位置是否为null，如果是 null 直接存入
        // ④ 如果不为null，表示有元素，则调用 equals 方法比较相等，则不存;不相等，则存入数组
        // ⑤ JDK8之前，新元素存入数组，占老元素位置，老元素挂下面 JDK8 开始之后，新元素直接挂在老元素下面

        // 2、JDK8 开始，哈希表 = 数组 + 链表 + 红黑树
        // JDK8 开始，当链表长度超过8，且数组长度 >= 64 时，自动将链表转成红黑树

        /*--------------------- HashSet 去重复机制 ---------------------*/
        // Hashset 集合默认不能对内容一样的两个不同对象去重复!
        // 问题：如何让 HashSet 认为两个内容一样对象是重复的？
        // 答：必须重写对象的 hashcode() 和 equals() 方法
        // 1、重写前
        HashSet<Person> hashSet = new HashSet<>();
        hashSet.add(new Person("张三", 21));
        hashSet.add(new Person("李四", 21));
        hashSet.add(new Person("李四", 21));
        hashSet.add(new Person("王五", 22));
        System.out.println("重写前 -- " + hashSet); // 重写前 -- [Person{name='李四', age=21}, Person{name='王五', age=22}, Person{name='张三', age=21}, Person{name='李四', age=21}]

        // 2、重写后
        HashSet<Person1> hashSet1 = new HashSet<>();
        hashSet1.add(new Person1("张三", 21));
        hashSet1.add(new Person1("李四", 21));
        hashSet1.add(new Person1("李四", 21));
        hashSet1.add(new Person1("王五", 22));
        System.out.println("重写后 -- " + hashSet1); // 重写后 -- [Person1(name=李四, age=21), Person1(name=张三, age=21), Person1(name=王五, age=22)]
    }
}

@AllArgsConstructor
@NoArgsConstructor
@ToString
class Person {
    private String name;
    private int age;
}

@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
class Person1 {
    private String name;
    private int age;
}

